package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"strings"
)

const (
	JWT_SECRET="ASGJK4TQ15AF4235590JSA"
)

var (
	DefaultHeader = JWTHeader{
		Algo: "HS256",
		Type: "JWT",
	}
)

type JWTHeader struct {
	Algo string `json:"alg"`
	Type string `json:"typ"`
}

type JWTPayload struct {
	Id          string         `json:"jti"`
	Issue       string         `json:"iss"`
	Audience    string         `json:"aud"`
	Subject     string         `json:"sub"`
	IssueAt     int64          `json:"iat"`
	NotBefore   int64          `json:"nbf"`
	Expiration  int64          `json:"exp"`
	UserDefined map[string]any `json:"ud"`
}

func GenJWT(header JWTHeader, payload JWTPayload, secret string) (string, error) {
	var part1, part2, signature string
	// header转为json，然后进行Base64编码
	bs1, err:=json.Marshal(header)
	if err!=nil{
		return "", err
	}
	// 这里没使用stdEncoding， RawURLEncoding结果不会包含=+等url中的字符
	part1 = base64.RawURLEncoding.EncodeToString(bs1)
	bs2, err:=json.Marshal(payload)
	if err!=nil{
		return "", err
	}
	part2 = base64.RawURLEncoding.EncodeToString(bs2)
	// 基于sha256的哈希认证算法。任意长度的字符串经过sha256之后变成256bits
	h:=hmac.New(sha256.New, []byte(secret))
	h.Write([]byte(part1+"."+part2))
	signature=base64.RawURLEncoding.EncodeToString(h.Sum(nil))
	return part1+"."+part2+"."+signature, nil
}

func VerifyJWT(token string, secret string) (*JWTHeader, *JWTPayload, error) {
	parts:=strings.Split(token, ".")
	if len(parts) !=3{
		return nil, nil, fmt.Errorf("token是%d部分，不合法", len(parts))
	}
	// 进行哈希签名验证
	h:=hmac.New(sha256.New, []byte(secret))
	h.Write([]byte(parts[0]+"."+parts[1]))
	signature:=base64.RawURLEncoding.EncodeToString(h.Sum(nil))
	if signature!=parts[2] {
		return nil, nil, fmt.Errorf("身份校验失败")
	}
	var part1, part2 []byte
	var err error
	part1, err=base64.RawURLEncoding.DecodeString(parts[0])
	if err!=nil{
		return nil,nil, fmt.Errorf("header Base64反解失败")
	}
	part2, err=base64.RawURLEncoding.DecodeString(parts[1])
	if err!=nil{
		return nil,nil, fmt.Errorf("payload Base64反解失败")
	}
	var header JWTHeader
	var payload JWTPayload
	err = json.Unmarshal(part1, &header)
	if err!=nil{
		return nil,nil, fmt.Errorf("header json反解失败")
	}
	err = json.Unmarshal(part2, &payload)
	if err!=nil{
		return nil,nil, fmt.Errorf("payload json反解失败")
	}
	return &header, &payload, nil
}